home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 2010 April
/
PCWorld0410.iso
/
pluginy Firefox
/
9675
/
9675.xpi
/
chrome
/
content
/
simpletimer-countdown.js
< prev
next >
Wrap
Text File
|
2009-11-17
|
23KB
|
586 lines
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Simple Timer.
*
* The Initial Developer of the Original Code is
* George Bradt.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
var SimpleTimerCountdown = {
// For reference, not used
countdownTimer: {timeDisplay: "",
recurring: false,
description: "",
timeMilli: 0,
timeFinishedMilli: 0,
paused: false
},
countdownSep: "\x1D", // used to separate countdowns in pref.
// Called when loading Countdown time entry dialog.
onLoadCountdown: function() {
var strbundle = document.getElementById("simtim-strings");
var prefs = Components.classes["@mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefService).
getBranch("extensions.simpletimer@grbradt.org.");
var Application = Components.classes["@mozilla.org/fuel/application;1"].
getService(Components.interfaces.fuelIApplication);
var countdownTable = [];
document.getElementById("simtim-tboxCountdownHours").value =
prefs.getIntPref("countdownHours");
document.getElementById("simtim-tboxCountdownMinutes").value =
prefs.getIntPref("countdownMinutes");
document.getElementById("simtim-tboxCountdownSeconds").value =
prefs.getIntPref("countdownSeconds");
if ( Application.storage.has("countdownTable") ) {
countdownTable = Application.storage.get("countdownTable", "ERR");
if ( countdownTable === "ERR" ) {
alert(strbundle.getString("alert.error.loading.countdowns"));
return;
}
}
else {
alert(strbundle.getString("alert.error.loading.countdowns"));
return;
}
var treeChildren = document.getElementById("simtim-treeItems");
// Clear the old tree data.
this.onDeleteAllCountdown();
for ( var i in countdownTable ) {
this.addTreeRow(treeChildren, countdownTable[i]);
}
},
// Called when Add/OK button is clicked.
onAddOkCountdown: function() {
if ( this.onAddCountdown() ) {
this.onOKCountdown();
window.close();
}
},
// Called when Add button is clicked.
onAddCountdown: function() {
var strbundle = document.getElementById("simtim-strings");
var hours = document.getElementById("simtim-tboxCountdownHours").value;
var minutes = document.getElementById("simtim-tboxCountdownMinutes").value;
var seconds = document.getElementById("simtim-tboxCountdownSeconds").value;
if ( hours === "0" &&
minutes === "0" &&
seconds === "0" ) {
alert(strbundle.getString("alert.warning.nonzero.user"));
return false;
}
var timeDisplay = this.padTime(hours) + ":" + this.padTime(minutes) + ":" + this.padTime(seconds);
var timeMilli = this.convertTimeToMilli(hours, minutes, seconds);
var descr = document.getElementById("simtim-tboxCountdownDescr").value;
var recurring = document.getElementById("simtim-cboxCountdownRecurring").checked;
var tree = document.getElementById("simtim-treeCountdown");
var boxobject = tree.boxObject;
boxobject.QueryInterface(Components.interfaces.nsITreeBoxObject);
var treeChildren = document.getElementById("simtim-treeItems");
var treeItems = treeChildren.hasChildNodes() ? treeChildren.childNodes: null;
var data = {timeDisplay: timeDisplay, recurring: recurring, description: descr,
timeMilli: timeMilli, timeFinishedMilli: 0, paused: false};
this.addTreeRow(treeChildren, data);
// Select the added row.
var rowIndex = treeItems ? treeItems.length - 1 : 0;
tree.view.selection.select(rowIndex);
// Ensure the added/updated row is visible, tree displays 5 rows (unless dlg stretched).
if ( treeItems && treeItems.length > 5 ) {
boxobject.ensureRowIsVisible(rowIndex);
}
// Clear the description textbox.
document.getElementById("simtim-tboxCountdownDescr").value = "";
return true;
},
// Add a timer to the tree.
addTreeRow: function(treeChildren, data) {
var item = document.createElement("treeitem");
var row = document.createElement("treerow");
var cell;
// First cell is "timeDisplay", not editable.
cell = document.createElement("treecell");
cell.setAttribute("label", data.timeDisplay);
cell.setAttribute("value", data.timeMilli);
cell.setAttribute("timeFinishedMilli", data.timeFinishedMilli);
cell.setAttribute("editable", "false");
row.appendChild(cell);
// Second cell is "recurring", displayed as a checkbox.
cell = document.createElement("treecell");
cell.setAttribute("value", data.recurring);
row.appendChild(cell);
// Third cell is "descr", the optional description. Stash paused.
cell = document.createElement("treecell");
cell.setAttribute("label", data.description);
cell.setAttribute("value", data.paused);
row.appendChild(cell);
// Add the treerow onto treeitem, append item.
item.appendChild(row);
treeChildren.appendChild(item);
},
// Called when Delete button is clicked.
onDeleteCountdown: function() {
var strbundle = document.getElementById("simtim-strings");
var tree = document.getElementById("simtim-treeCountdown");
if ( tree.currentIndex < 0 ) {
// User didn't make a selection.
alert(strbundle.getString("alert.warning.no.item.selected"));
}
else {
var start = {};
var end = {};
var treeItem;
var numRanges = tree.view.selection.getRangeCount();
// Start with the last selection range and work up.
for ( var i = numRanges - 1; i >= 0; i-- ) {
tree.view.selection.getRangeAt(i,start,end);
// Within a range, delete from the bottom up.
for ( var j = end.value; j >= start.value; j-- ) {
treeItem = tree.view.getItemAtIndex(j);
treeItem.parentNode.removeChild(treeItem);
}
}
}
},
// Called when Del All button is clicked.
onDeleteAllCountdown: function() {
var treeChildren = document.getElementById("simtim-treeItems");
// Remove from the bottom.
while ( treeChildren.hasChildNodes() ) {
treeChildren.removeChild(treeChildren.lastChild);
}
},
// Save the favourite timers list in a pref.
// Called when Save List button is clicked.
onSaveList: function() {
var strbundle = document.getElementById("simtim-strings");
var str = Components.classes["@mozilla.org/supports-string;1"].
createInstance(Components.interfaces.nsISupportsString);
// Objects stored as JSON strings in the pref.
var json = Components.classes["@mozilla.org/dom/json;1"].
createInstance(Components.interfaces.nsIJSON);
var treeChildren = document.getElementById("simtim-treeItems");
if ( treeChildren.hasChildNodes() ) {
// Get confirmation.
var button = confirm(strbundle.getString("confirm.save.timer.list"));
if ( !button ) {
// User didn't click OK.
return;
}
// Build pref string of all timers from dialog Countdown timers tree.
var row, timeDisplay, recurring, description, paused,
timeMilli, timeFinishedMilli, timeNode;
var prefString = "";
var currTimeMilli = new Date().getTime();
var treeItems = treeChildren.childNodes;
var len = treeItems.length;
for ( var i = 0; i < len; i++ ) {
row = treeItems[i].firstChild;
timeNode = row.firstChild;
timeDisplay = timeNode.getAttribute("label");
timeMilli = parseInt(timeNode.getAttribute("value"), 10);
// Convert string attribute to boolean.
recurring = ( row.firstChild.nextSibling.getAttribute("value") === "true" ) ?
true : false;
description = row.lastChild.getAttribute("label");
try {
prefString += json.encode( {timeDisplay: timeDisplay, recurring: recurring,
description: description, timeMilli: timeMilli, timeFinishedMilli: 0,
paused: false} ) + this.countdownSep;
}
catch(e) {
alert(strbundle.getString("alert.error.encoding.timer"));
return;
}
}
// Remove last separator.
if ( prefString ) {
prefString = prefString.substring(0, prefString.length - 1);
}
str.data = prefString;
window.opener.SimpleTimer.prefs.setComplexValue("favCountdowns",
Components.interfaces.nsISupportsString, str);
}
else {
alert(strbundle.getString("msg.no.timers"));
}
},
// Load the favourite timers list from pref.
// Called when Load List button is clicked.
onLoadList: function() {
var strbundle = document.getElementById("simtim-strings");
if ( !window.opener.SimpleTimer.favCountdowns ) {
alert(strbundle.getString("msg.timers.no.list"));
return;
}
// Objects stored as JSON strings in the pref.
var json = Components.classes["@mozilla.org/dom/json;1"].
createInstance(Components.interfaces.nsIJSON);
var favCountdownArray = window.opener.SimpleTimer.favCountdowns.split(this.countdownSep);
var treeChildren = document.getElementById("simtim-treeItems");
var tempArray = [];
for ( var i in favCountdownArray ) {
try {
tempArray[i] = json.decode(favCountdownArray[i]);
}
catch(e) {
alert(strbundle.getString("alert.error.decoding.timer"));
return;
}
this.addTreeRow(treeChildren, tempArray[i]);
}
},
// Pad a display time with zero if necessary.
padTime: function(time) {
return ( ( time < 10 ) ? "0" + time : time );
},
// Convert a time to milliseconds.
convertTimeToMilli: function(hrs, mins, secs) {
return ( ( hrs * 60 * 60 * 1000 ) + ( mins * 60 * 1000 ) + ( secs * 1000 ) );
},
// Called when user clicks OK.
onOKCountdown: function() {
window.opener.SimpleTimer.prefs.setIntPref("countdownHours",
document.getElementById("simtim-tboxCountdownHours").value);
window.opener.SimpleTimer.prefs.setIntPref("countdownMinutes",
document.getElementById("simtim-tboxCountdownMinutes").value);
window.opener.SimpleTimer.prefs.setIntPref("countdownSeconds",
document.getElementById("simtim-tboxCountdownSeconds").value);
this.buildCountdownTable();
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"].getService();
var wmed = wm.QueryInterface(Components.interfaces.nsIWindowMediator);
var enumerator = wmed.getEnumerator("navigator:browser");
while ( enumerator.hasMoreElements() ) {
var win = enumerator.getNext();
win.SimpleTimer.cancelTimerInProgress();
if ( win.SimpleTimer.getCountdownTable() ) {
win.SimpleTimer.setCountdownTimer();
}
}
},
// Construct an array of countdown timer objects.
// Called when the user clicks OK or Add/OK.
buildCountdownTable: function() {
var Application = Components.classes["@mozilla.org/fuel/application;1"].
getService(Components.interfaces.fuelIApplication);
var treeChildren = document.getElementById("simtim-treeItems");
var countdownTable = [];
if ( treeChildren.hasChildNodes() ) {
// Build table of all timers from dialog Countdown timers tree.
var row, timeDisplay, recurring, description, paused,
timeMilli, timeFinishedMilli, timeNode;
var currTimeMilli = new Date().getTime();
var treeItems = treeChildren.childNodes;
var len = treeItems.length;
for ( var i = 0; i < len; i++ ) {
row = treeItems[i].firstChild;
timeNode = row.firstChild;
timeDisplay = timeNode.getAttribute("label");
timeMilli = parseInt(timeNode.getAttribute("value"), 10);
timeFinishedMilli = parseInt(timeNode.getAttribute("timeFinishedMilli"), 10);
// Convert string attribute to boolean.
recurring = ( row.firstChild.nextSibling.getAttribute("value") === "true" ) ?
true : false;
// Check if an existing timer expired while dialog open.
if ( timeFinishedMilli > 0 && currTimeMilli > timeFinishedMilli ) {
if ( recurring ) {
// Cannot use timeMilli, since it changes if paused.
var timeDisplayMilli = SimpleTimer.convertClockToMilli(timeDisplay);
timeFinishedMilli += timeDisplayMilli *
Math.ceil((currTimeMilli - timeFinishedMilli) / timeDisplayMilli);
}
else {
continue;
}
}
description = row.lastChild.getAttribute("label");
paused = ( row.lastChild.getAttribute("value") === "true" ) ?
true : false;
// Don't use i for index, as some tree items may be bypassed.
countdownTable[countdownTable.length] = {timeDisplay: timeDisplay,
recurring: recurring,
description: description,
timeMilli: timeMilli,
timeFinishedMilli: timeFinishedMilli,
paused: paused
};
}
}
Application.storage.set("countdownTable", countdownTable);
},
// Construct an array of countdown objects from the countdowns pref,
// and store via FUEL. Called at startup.
buildCountdownTableFromPref: function(countdowns) {
var strbundle = document.getElementById("simtim-strings");
var currTimeMilli = new Date().getTime();
// Objects stored as JSON strings in the pref.
var json = Components.classes["@mozilla.org/dom/json;1"].
createInstance(Components.interfaces.nsIJSON);
var eventDescription, eventRecurring;
var tempArray = [];
var expiredArray = [];
var countdownTable = [];
var countdownArray = countdowns.split(this.countdownSep);
for ( var i in countdownArray ) {
tempArray[i] = json.decode(countdownArray[i]);
if ( !tempArray[i].hasOwnProperty('paused') ) {
tempArray[i].paused = false;
}
// Exclude timers that expired while browser closed. Always include recurring,
// adjusting its finish time if necessary.
if ( tempArray[i].recurring && currTimeMilli >= tempArray[i].timeFinishedMilli ) {
tempArray[i].timeFinishedMilli +=
tempArray[i].timeMilli *
Math.ceil((currTimeMilli - tempArray[i].timeFinishedMilli) / tempArray[i].timeMilli);
}
// Paused timer will get a valid finish time only when resumed.
// This will sort to the top.
if ( tempArray[i].paused ) {
tempArray[i].timeFinishedMilli = 0;
}
if ( currTimeMilli <= tempArray[i].timeFinishedMilli ||
tempArray[i].paused ) {
countdownTable[countdownTable.length] = tempArray[i];
}
else {
// Expired, save for display in slider alert.
expiredArray.push({timeDisplay: tempArray[i].timeDisplay,
description: tempArray[i].description});
if ( SimpleTimer.eventLogging ) {
eventDescription = ( tempArray[i].description ) ?
tempArray[i].description :
strbundle.getString("msg.none");
eventRecurring = ( tempArray[i].recurring ) ?
strbundle.getString("msg.yes") :
strbundle.getString("msg.no");
// Pass event type, event time, recurring, status, description, URL(N/A).
SimpleTimerEventLog.logEvent(strbundle.getString("msg.countdown"),
tempArray[i].timeDisplay,
eventRecurring,
strbundle.getString("msg.expired"),
eventDescription,
strbundle.getString("msg.not.applicable"));
}
}
}
// If opening another browser window, user would have seen the expired alerts.
if ( !SimpleTimer.otherBrowserWindowOpen() ) {
if ( countdownTable.length === 0 ) {
var params = { displayItems: expiredArray, msg: strbundle.getString("msg.countdown.timers.none" )};
setTimeout(SimpleTimerSliderAlert.addMessageToQueue, 5000, params);
setTimeout("SimpleTimer.playSound(3)", 5000);
}
else if (countdownTable.length !== countdownArray.length ) {
params = { displayItems: expiredArray, msg: strbundle.getString("msg.countdown.timers.some" )};
setTimeout(SimpleTimerSliderAlert.addMessageToQueue, 5000, params);
setTimeout("SimpleTimer.playSound(3)", 5000);
}
else {
params = { displayItems: null, msg: strbundle.getString("msg.countdown.timers.all" )};
setTimeout(SimpleTimerSliderAlert.addMessageToQueue, 5000, params);
setTimeout("SimpleTimer.playSound(3)", 5000);
}
}
Application.storage.set("countdownTable", countdownTable);
if ( countdownTable.length !== countdownArray.length ) {
// Update pref in case another window opened.
this.updateCountdownPref();
}
},
// Write countdowns pref from countdown table. Called from SimpleTimer.
updateCountdownPref: function() {
var prefs = Components.classes["@mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefService).
getBranch("extensions.simpletimer@grbradt.org.");
// For Unicode.
var str = Components.classes["@mozilla.org/supports-string;1"].
createInstance(Components.interfaces.nsISupportsString);
var Application = Components.classes["@mozilla.org/fuel/application;1"].
getService(Components.interfaces.fuelIApplication);
var countdownTable = [];
if ( Application.storage.has("countdownTable") ) {
countdownTable = Application.storage.get("countdownTable", "ERR");
if ( countdownTable === "ERR" ) {
alert(strbundle.getString("alert.error.loading.countdowns"));
return;
}
}
else {
alert(strbundle.getString("alert.error.loading.countdowns"));
return;
}
// Objects stored as JSON strings in the pref.
var json = Components.classes["@mozilla.org/dom/json;1"].
createInstance(Components.interfaces.nsIJSON);
var prefString = "";
for ( var i in countdownTable ) {
prefString += json.encode(countdownTable[i]) + this.countdownSep;
}
// Remove last separator.
if ( prefString ) {
prefString = prefString.substring(0, prefString.length - 1);
}
str.data = prefString;
SimpleTimer.prefs.setComplexValue("countdowns",
Components.interfaces.nsISupportsString, str);
},
// Sort the countdown table on objects timeFinishedMilli property.
// Called from SimpleTimer.setCountdownTimer().
sortCountdownTable: function(a, b) {
var x = a.timeFinishedMilli;
var y = b.timeFinishedMilli;
return ( (x < y) ? -1 : ( (x > y) ? 1 : 0 ) );
},
// Dump to console.
dumpCountdownObject: function (countdownTimer) {
this.debug("\nCountdown timer data:");
this.debug("Countdown Time for Display: " + countdownTimer.timeDisplay);
this.debug("Recurring?: " + countdownTimer.recurring);
this.debug("Description: " + countdownTimer.description);
this.debug("Countdown time (millisecs): " + countdownTimer.timeMilli);
this.debug("Countdown finish time (millisecs): " + countdownTimer.timeFinishedMilli);
},
// Debug messages to console.
debug: function (aMsg) {
setTimeout(function() { throw new Error("[debug] " + aMsg); }, 0);
}
};